package pl.skubicha.service;

import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import pl.skubicha.domain.Users;
import pl.skubicha.exceptions.EntityConstraintException;
import pl.skubicha.exceptions.UserNotFoundException;
import pl.skubicha.repository.UserRepository;
import pl.skubicha.response.UserDTO;
import pl.skubicha.utils.UserMapper;

@Service
public class UserRepositoryService implements UserService {

	private static Logger logger = Logger.getLogger( UserRepositoryService.class );

	@Autowired
	private UserRepository userRepository;

	@Override
	@Transactional( readOnly = true )
	public List< Users > findAllTeachers() {
		logger.debug( "Wyszukuję wszystkich nauczycieli." );
		return userRepository.findAllTeachers();
	}

	@Override
	@Transactional( readOnly = true )
	public Page< Users > findAllTeachers( final Pageable page ) {
		logger.debug( "Wyszukuję wszystkich nauczycieli. Stronicowanie" );
		return userRepository.findAllTeachers( page );
	}

	@Override
	@Transactional( readOnly = true )
	public Page< Users > findAllTeachersMatching( final String searchString, final Pageable page ) {
		logger.debug( "Wyszukuję wszystkich nauczycieli zawierających " + "%" + searchString + "%" );
		return userRepository.findAllTeachersBySearchString( "%" + searchString + "%", page );
	}

	@Override
	@Transactional( readOnly = true )
	public List< Users > findAllStudents() {
		logger.debug( "Wyszukuję wszystkich studentów." );
		return userRepository.findAllStudents();
	}

	@Override
	@Transactional( readOnly = true )
	public Page< Users > findAllStudents( final Pageable page ) {
		logger.debug( "Wyszukuję wszystkich studentów. Stronicowanie" );
		return userRepository.findAllStudents( page );
	}

	@Override
	@Transactional( readOnly = true )
	public Page< Users > findAllStudentsInGroup( final Integer id, final Pageable page ) {
		logger.debug( "Wyszukuję wszystkich studentów w grupie o id: " + id );
		return userRepository.findAllStudentsInGroup( id, page );
	}

	@Override
	@Transactional( readOnly = true )
	public List< Users > findAllStudentsInGroup( final Integer id ) {
		logger.debug( "Wyszukuję wszystkich studentów w grupie o id: " + id );
		return userRepository.findAllStudentsInGroup( id );
	}

	@Override
	@Transactional( readOnly = true )
	public List< Users > findAllStudentsInGroupAndSubject( final Integer idGroup, final Integer idSubject ) {
		return userRepository.findAllStudentsInGroupAndSubject( idGroup, idSubject );
	}

	@Override
	@Transactional( readOnly = true )
	public Page< Users > findAllStudentsMatching( final String searchString, final Pageable page ) {
		logger.debug( "Wyszukuję wszystkich studentów zawierających " + "%" + searchString + "%" );
		return userRepository.findAllStudentsBySearchString( searchString, page );
	}

	@Override
	@Transactional( readOnly = true )
	public Users findById( final Integer id ) throws UserNotFoundException {
		logger.debug( "Wyszukuję użytkownika o id: " + id );
		final Users user = userRepository.findOne( id );

		if ( user == null ) {
			logger.debug( "Nie znaleziono użytkownika o id: " + id );
			throw new UserNotFoundException( "Nie znaleziono użytkownika o id: " + id );
		}

		return user;
	}

	@Transactional( readOnly = true )
	@Override
	public Users findByLogin( final String login ) throws UserNotFoundException {
		logger.debug( "Wyszukuję użytkownika o loginie: " + login );
		final Users user = userRepository.findByLogin( login );

		if ( user == null ) {
			logger.debug( "Nie znaleziono użytkownika o loginie: " + login );
			throw new UserNotFoundException( "Nie znaleziono użytkownika o loginie: " + login );
		}

		return user;
	}

	@Override
	public Users create( final UserDTO created ) {
		logger.debug( "Tworzę użytkownika: " + created );
		final Users user = UserMapper.map( created );
		return userRepository.save( user );
	}

	@Override
	public Users create( final Users created ) {
		return userRepository.save( created );
	}

	@Transactional( rollbackFor = UserNotFoundException.class )
	@Override
	public Users update( final UserDTO updated ) throws UserNotFoundException {
		final Users user = findById( updated.getId() );

		if ( user == null ) {
			logger.debug( "Nie znaleziono użytkownika o id: " + updated.getId() );
			throw new UserNotFoundException( "Nie znaleziono użytkownika o id: " + updated.getId() );
		}

		user.update( updated.getUserName(), updated.getFirstName(), updated.getLastName(), updated.getEmail(), updated.isStatus(), updated.getAlbumNumber(), updated.getGroups(), updated.getGrades() );

		return user;
	}

	@Transactional( rollbackFor = { UserNotFoundException.class, EntityConstraintException.class } )
	@Override
	public Users delete( final Integer id ) throws UserNotFoundException, EntityConstraintException {

		final Users deleted = findById( id );

		if ( deleted == null ) {
			logger.debug( "Nie znaleziono użytkownika o id: " + id );
			throw new UserNotFoundException();
		}

		if ( CollectionUtils.isNotEmpty( deleted.getSubjects() ) || CollectionUtils.isNotEmpty( deleted.getPartialGrades() ) ) {
			logger.debug( "Użytkownik " + deleted.getLogin() + " posiada referencje do przedmiotów!" );
			throw new EntityConstraintException( "Użytkownik " + deleted.getLogin() + " posiada referencje do przedmiotów!" );
		}

		userRepository.delete( deleted );
		return deleted;
	}
}
